#include "teststdafx.h"
#include "stdafx.h"
#include <gtest/gtest.h>

#include "Business/Policy/CallAuctionBusiness.h"
#include "Utils/TimeoutNotifier.h"
#include "Utils/FastBlockQueue.h"
#include "Business/QueueContext.h"
#include "Repository/CancellationRepository.h"
#include "Repository/DealingRepository.h"
#include "Service/MarketStorage.h"
#include "Business/Customer.h"
#include "Business/Command.h"
#include "Business/ExchangeNotify.h"
#include "Business/RequestTimeout.h"

using namespace std;

class CallAuctionBusinessTest : public testing::Test
{
protected:

	virtual void SetUp()
	{
		HANDLE hQuit = ::CreateEvent(NULL,TRUE,FALSE,NULL);
		m_customer.reset(new Customer("","",""));
		m_customer->SetOrginalAmount(10000.00);
		m_requestQueue.reset(FastBlockQueue::Create(hQuit));
		m_businessQueue.reset(FastBlockQueue::Create(hQuit));
		m_uiQueue.reset(FastBlockQueue::Create(hQuit));
		m_highTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_waitTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_dealingRepository.reset(new DealingRepository());
		m_cancellationRepository.reset(new CancellationRepository());
		m_queueContext.reset(new QueueContext(*m_requestQueue,*m_businessQueue,*m_uiQueue,*m_highTimerQueue,*m_waitTimerQueue));
		m_timeoutNotifier.reset(new TimeoutNotifier());

		InitMarket();

		Band bearish(80,120,MORE_LOWER);
		Band bullish(180,140,MORE_UPPER);
		m_business.reset(
			new CallAuctionBusiness(*m_customer,
				CallAuctionArgument(ArbitrageContracts(0,1),10,bearish,bullish,20000,21000,false,5,5),
				m_marketStorage,
				*m_queueContext,
				*m_dealingRepository,
				*m_cancellationRepository,
				*m_timeoutNotifier,
				m_contractMatheres
			)
		);
	}
	virtual void TearDown()
	{
	}
	void InitMarket()
	{
		m_marketStorage.Save(CreateBearishMarket0());
		m_marketStorage.Save(CreateBearishMarket1());
	}

	Market CreateBearishMarket0()
	{
		Variety variety("zn1010",10,10);
		double lastPrice = 18550;
		Prices buyPrices;
		buyPrices[0] = Price(18550,10);
		Prices sellPrices;
		sellPrices[0] = Price(18540,5);
		double upperLimit = 40000;
		double lowerLimit = 20000;
		double preSettlementPrice  = 20000;
		return Market(0,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
	}
	Market CreateBearishMarket1()
	{
		Variety variety("zn1011",10,10);
		double lastPrice = 18690;
		Prices buyPrices;
		buyPrices[0] = Price(18690,2);
		Prices sellPrices;
		sellPrices[0] = Price(18680,2);
		double upperLimit = 40000;
		double lowerLimit = 20000;
		double preSettlementPrice  = 30000;
		return Market(1,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
	}

	void OnPendingMarket(int contract,Direction::TYPE direction,int price,int quantity)
	{
		PendingMarket market;
		market.contract = contract;
		market.direction = direction;
		market.price = price;
		market.quantity = quantity; 
		m_contractMatheres.Update(market);
	}

	void OnNearbyBuy(int price,int quantity)
	{
		OnPendingMarket(0,Direction::BUY,price,quantity);
	}

	void OnNearbySell(int price,int quantity)
	{
		OnPendingMarket(0,Direction::SELL,price,quantity);
	}

	void OnFartherBuy(int price,int quantity)
	{
		OnPendingMarket(1,Direction::BUY,price,quantity);
	}

	void OnFartherSell(int price, int quantity)
	{
		OnPendingMarket(1,Direction::SELL,price,quantity);
	}

	void OnBearishPendingMarkets()
	{
		OnFartherBuy(18700,10);OnFartherSell(18600,5);
		OnFartherBuy(18690,10);OnFartherSell(18620,15);
		OnFartherBuy(18680,10);OnFartherSell(18630,15);
		OnFartherBuy(18670,10);OnFartherSell(18640,5);
		OnFartherBuy(18660,10);OnFartherSell(18660,10); //18660

		OnNearbyBuy(18650,10);OnNearbySell(18550,5);
		OnNearbyBuy(18640,10);OnNearbySell(18560,15);
		OnNearbyBuy(18630,10);OnNearbySell(18570,15);
		OnNearbyBuy(18620,10);OnNearbySell(18580,5);
		OnNearbyBuy(18610,15);OnNearbySell(18610,5); //18610
	}

	void OnCommand(Command::TYPE type)
	{
		Command cmd = {0};
		cmd.type = type;
		cmd.business = m_business.get();
		m_business->OnCommand(cmd);
	}

	void OnExchangeStatus(ExchangeStatus::FLAG exchangeStatus)
	{
		m_business->OnExchangeStatus(exchangeStatus);
	}

	void OnBaseTimeout()
	{
		RequestTimeout timeout = RequestTimeout::CreateBase(m_business.get());
		m_business->OnTimeout(timeout);
	}

	void OnAllOrdered()
	{
		if (m_queueContext->GetRequestQueue().Size() < 2)
		{
			return;
		}
		m_fartherOpenDealing = OnOrdered();
		m_nearbyOpenDealing = OnOrdered();
	}

	Dealing* OnOrdered()
	{
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		Dealing* dealing = m_dealingRepository->Get(((Dealing*)item.data)->GetLocalId());
		dealing->OnOrdered(FT("%d",dealing->GetLocalId()));
		m_business->OnDealing(*dealing);
		return dealing;
	}

	Dealing* OnCancelled()
	{
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		Dealing* dealing = m_dealingRepository->Get(((Cancellation*)item.data)->GetOrderLocalId());
		dealing->OnCancelSuccess(0);
		m_business->OnDealing(*dealing);
		return dealing;
	}

	void OnAllDealed()
	{
		OnDealed(m_fartherOpenDealing);
		OnDealed(m_nearbyOpenDealing);
	}

	void OnDealed(Dealing* dealing, int quantity = 0)
	{
		FT systemNo("%d",dealing->GetLocalId());
		Trade fartherTrade(*dealing,
			dealing->GetOrderPrice(),
			quantity == 0 ? dealing->GetOrderQuantity() : quantity,
			systemNo);
		dealing->OnTrade(fartherTrade);
		m_business->OnTrade(fartherTrade);
		m_business->OnDealing(*dealing);
	}
	void OnAllCancelled()
	{
		if (m_queueContext->GetRequestQueue().Size() < 2)
		{
			return;
		}
		m_fartherOpenDealing = OnCancelled();
		m_nearbyOpenDealing = OnCancelled();

	}
	void OnNearbyCancelled()
	{
		if (m_queueContext->GetRequestQueue().Size() < 1)
		{
			return;
		}
		m_nearbyOpenDealing = OnCancelled();

	}

	void OnBeairshOffsetMarkets()
	{
		m_business->OnMarket(CreateBearishMarket1());
	}

	MarketStorage m_marketStorage;
	auto_ptr<FastBlockQueue> m_requestQueue;
	auto_ptr<FastBlockQueue> m_businessQueue;
	auto_ptr<FastBlockQueue> m_uiQueue;
	auto_ptr<FastBlockQueue> m_highTimerQueue;
	auto_ptr<FastBlockQueue> m_waitTimerQueue;
	auto_ptr<Customer> m_customer;
	auto_ptr<CallAuctionBusiness> m_business;
	auto_ptr<DealingRepository> m_dealingRepository;
	auto_ptr<CancellationRepository> m_cancellationRepository;
	auto_ptr<QueueContext> m_queueContext;
	auto_ptr<TimeoutNotifier> m_timeoutNotifier;
	ContractMatcheres m_contractMatheres;

	Dealing* m_fartherOpenDealing;
	Dealing* m_nearbyOpenDealing;

	void foo();
};

TEST_F(CallAuctionBusinessTest,BearishOffsetTest)/*
void CallAuctionBusinessTest::foo() /* */
{
// 	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
// 	OnBearishPendingMarkets();
// 	OnCommand(Command::START_COMMAND);
// 	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
// 	OnExchangeStatus(ExchangeStatus::AUCTION_ORDERING);
// 	OnBaseTimeout();
// 	EXPECT_STREQ("sent",m_business->GetSnapshot().GetStatus());
//  	OnAllOrdered();
//  	OnAllDealed();
// 	OnExchangeStatus(ExchangeStatus::CONTINOUS);
//  	EXPECT_STREQ("opened",m_business->GetSnapshot().GetStatus());
//  
//  	OnCommand(Command::CLEAR_COMMAND);
//  	EXPECT_STREQ("wait to clear",m_business->GetSnapshot().GetStatus());
// 
// 	for (int i = 1; i <= 5; ++i)
// 	{
// 		OnBeairshOffsetMarkets();
// 		EXPECT_STREQ("minor offset sent",m_business->GetSnapshot().GetStatus());
// 
// 		Dealing* offsetDealing = OnOrdered();
// 		EXPECT_EQ(2,offsetDealing->GetOrderQuantity());
// 
// 		EXPECT_STREQ("minor offset ordered",m_business->GetSnapshot().GetStatus());
// 		EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());
// 		{
// 			bool quitFlag = false;
// 			QueueItem& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
// 			EXPECT_EQ(QueueItem::CANCELLATION,item.type);
// 		}
// 		Trade minorOffsetTrade(*offsetDealing,offsetDealing->GetOrderPrice(),offsetDealing->GetOrderQuantity(),offsetDealing->GetSystemNo());
// 		offsetDealing->OnTrade(minorOffsetTrade);
// 		m_business->OnTrade(minorOffsetTrade);
// 		m_business->OnDealing(*offsetDealing);
// 		EXPECT_STREQ("major offset sent",m_business->GetSnapshot().GetStatus());
// 		EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());
// 
// 		offsetDealing = OnOrdered();
// 		EXPECT_EQ(2,offsetDealing->GetOrderQuantity());
// 		Trade majorOffsetTrade(*offsetDealing,offsetDealing->GetOrderPrice(),offsetDealing->GetOrderQuantity(),offsetDealing->GetSystemNo());
// 		offsetDealing->OnTrade(majorOffsetTrade);
// 		m_business->OnTrade(majorOffsetTrade);
// 		m_business->OnDealing(*offsetDealing);
// 		EXPECT_EQ(10-i*2,m_business->GetSnapshot().GetMajorQuantity());
// 		EXPECT_EQ(10-i*2,m_business->GetSnapshot().GetMinorQuantity());
// 		if (i < 5 )
// 		{
// 			EXPECT_STREQ("wait to clear",m_business->GetSnapshot().GetStatus());
// 		}
// 		else
// 		{
// 			EXPECT_STREQ("end",m_business->GetSnapshot().GetStatus());
// 		}
// 	}
}

TEST_F(CallAuctionBusinessTest,UpdateArgumentTest)/*
void CallAuctionBusinessTest::foo() /* */
{
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	OnBearishPendingMarkets();
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	OnExchangeStatus(ExchangeStatus::AUCTION_ORDERING);
	OnBaseTimeout();
	EXPECT_STREQ("sent",m_business->GetSnapshot().GetStatus());
	OnAllOrdered();
	OnAllDealed();
	OnExchangeStatus(ExchangeStatus::CONTINOUS);
	EXPECT_STREQ("opened",m_business->GetSnapshot().GetStatus());

	OnCommand(Command::CLEAR_COMMAND);
	EXPECT_STREQ("wait to clear",m_business->GetSnapshot().GetStatus());

	Command cmd = {0};
	cmd.type = Command::UPDATE_ARGUMENT_COMMAND;
	cmd.business = m_business.get();
	CallAuctionArgument& argument = *(CallAuctionArgument*)cmd.data;
	argument = CallAuctionArgument(m_business->GetArgument().GetContracts(),
		m_business->GetArgument().GetMaxQuantity(),
		Band(210,220,MORE_LOWER),
		m_business->GetArgument().GetBullish(),
		m_business->GetArgument().GetMajorPrePrice(),
		m_business->GetArgument().GetMinorPrePrice(),false,5,5);
	m_business->OnCommand(cmd);

	OnBeairshOffsetMarkets();
	EXPECT_STREQ("wait to clear",m_business->GetSnapshot().GetStatus());

	argument = CallAuctionArgument(m_business->GetArgument().GetContracts(),
		m_business->GetArgument().GetMaxQuantity(),
		Band(80,120,MORE_LOWER),
		m_business->GetArgument().GetBullish(),
		m_business->GetArgument().GetMajorPrePrice(),
		m_business->GetArgument().GetMinorPrePrice(),false,5,5);
	m_business->OnCommand(cmd);	
	
	OnBeairshOffsetMarkets();
	EXPECT_STREQ("minor offset sent",m_business->GetSnapshot().GetStatus());
}


TEST_F(CallAuctionBusinessTest,AllCancelledTest)/*
void CallAuctionBusinessTest::foo() /* */
{
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	OnBearishPendingMarkets();
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	OnExchangeStatus(ExchangeStatus::AUCTION_ORDERING);
	OnBaseTimeout();
	EXPECT_STREQ("sent",m_business->GetSnapshot().GetStatus());
	OnAllOrdered();
	OnCommand(Command::CANCEL_COMMAND);
	EXPECT_STREQ("cancel sent",m_business->GetSnapshot().GetStatus());

	OnAllCancelled();
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());

}

TEST_F(CallAuctionBusinessTest,AllPartialCancelTest)/*
void CallAuctionBusinessTest::foo() /* */
{
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	OnBearishPendingMarkets();
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	OnExchangeStatus(ExchangeStatus::AUCTION_ORDERING);
	OnBaseTimeout();
	EXPECT_STREQ("sent",m_business->GetSnapshot().GetStatus());
	OnAllOrdered();
	OnDealed(m_fartherOpenDealing);
	OnCommand(Command::CANCEL_COMMAND);
	EXPECT_STREQ("cancel sent",m_business->GetSnapshot().GetStatus());
	EXPECT_EQ(1,m_requestQueue->Size());

	OnNearbyCancelled();
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());

}

TEST_F(CallAuctionBusinessTest,AllPartialCancelTest2)/*
void CallAuctionBusinessTest::foo() /* */
{
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	OnBearishPendingMarkets();
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	OnExchangeStatus(ExchangeStatus::AUCTION_ORDERING);
	OnBaseTimeout();
	EXPECT_STREQ("sent",m_business->GetSnapshot().GetStatus());
	OnAllOrdered();
	OnDealed(m_fartherOpenDealing,1);
	OnDealed(m_nearbyOpenDealing,1);
	OnCommand(Command::CANCEL_COMMAND);
	EXPECT_STREQ("cancel sent",m_business->GetSnapshot().GetStatus());
	EXPECT_EQ(2,m_requestQueue->Size());

	OnAllCancelled();
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());

}


TEST_F(CallAuctionBusinessTest,LimitPriceTest)/*
void CallAuctionBusinessTest::foo() /* */
{
	Band bearish(80,120,MORE_LOWER);
	Band bullish(180,140,MORE_UPPER);
	m_business.reset(
		new CallAuctionBusiness(*m_customer,
		CallAuctionArgument(ArbitrageContracts(0,1),10,bearish,bullish,20000,21000,true,7,7),
		m_marketStorage,
		*m_queueContext,
		*m_dealingRepository,
		*m_cancellationRepository,
		*m_timeoutNotifier,
		m_contractMatheres
		));

	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	OnBearishPendingMarkets();
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	OnExchangeStatus(ExchangeStatus::AUCTION_ORDERING);
	OnBaseTimeout();
	EXPECT_STREQ("sent",m_business->GetSnapshot().GetStatus());
	EXPECT_EQ(m_queueContext->GetRequestQueue().Size(), 2);
	m_fartherOpenDealing = OnOrdered();
	m_nearbyOpenDealing = OnOrdered();
	OnCommand(Command::CANCEL_COMMAND);
	EXPECT_STREQ("cancel sent",m_business->GetSnapshot().GetStatus());

	OnAllCancelled();
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());

}